package com.to8to.kitt.utils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;
import org.apache.thrift.TBase;
import org.apache.thrift.TFieldIdEnum;
import org.apache.thrift.meta_data.EnumMetaData;
import org.apache.thrift.meta_data.FieldMetaData;
import org.apache.thrift.meta_data.FieldValueMetaData;
import org.apache.thrift.meta_data.ListMetaData;
import org.apache.thrift.meta_data.MapMetaData;
import org.apache.thrift.meta_data.StructMetaData;
import org.apache.thrift.protocol.TType;

import com.to8to.commons.json.JSONArray;
import com.to8to.commons.json.JSONObject;
import com.to8to.commons.utils.ThriftUtil;

public class ThriftUtils {
	 private static <T extends TBase<?, F>, F extends TFieldIdEnum> T parseStruct(
				JSONObject fieldValue, StructMetaData structMetaData) throws Exception {
			return JsonNode2Thrift(fieldValue,(Class<T>) structMetaData.structClass);
		}
	    
		/**
		 * 当字段是map类型时，调用这个方法 【注】只支持String类型的Key,thrift本身可以支持Object类型,但JSONObject不支持
		 * 
		 * @param fieldValue
		 *            键值对容器，支持的键值对容器类型参见：{@link ThriftUtil.Type}
		 * @param mapMetaData
		 *            map类型的元数据，该对象包含key和value的 meta data
		 * @return HashMap对象
		 * @throws Exception 
		 */
		private static Map<String, Object> parseMap(JSONObject fieldValue,
				MapMetaData mapMetaData) throws Exception {
			Map<String, Object> tmap = new HashMap<String, Object>();

			Iterator<Map.Entry<String, Object>> iter = (Iterator<Entry<String, Object>>) fieldValue.entrySet();
			while(iter.hasNext())
			{
				Map.Entry<String, Object> e = iter.next();
				String field = e.getKey();
				Object val = e.getValue();
				Object tval = parseField(val, mapMetaData.valueMetaData);
				tmap.put(field, tval);
			}
			return tmap;
		}
		
		/**
		 * 当字段是List类型时，调用这个方法
		 * 
		 * @param fieldValue
		 *            字段值
		 * @param listMetaData
		 *            list类型的元数据，该对象包含所储元素的 meta data
		 * @throws Exception 
		 */
		private static List<Object> parseList(JSONArray fieldValue, ListMetaData listMetaData) throws Exception {
			List<Object> tlist = new ArrayList<Object>();
			for(int i = 0 ; i < fieldValue.size(); ++ i)
			{
				Object e = fieldValue.get(i);
				Object eleVal = parseField(e, listMetaData.elemMetaData);
				tlist.add(eleVal);
			}
			return tlist;
		}
		
		/**
		 * 当字段是枚举类型时，调用这个方法
		 */
		private static <T extends Enum<T>> Object parseEnum(JSONObject fieldValue,
				EnumMetaData enumMetaData) {
			String enumName = fieldValue.getString("name");
			try {
				Object result = Enum.valueOf((Class<T>) enumMetaData.enumClass,enumName);
				return result;
			} catch (Exception e) {
				
				return null;
			}
		}
		
	    /**
		 * 将字段（也支持集合的元素）解析成Thrift支持的对象
		 * 
		 * @param fieldValue
		 *            目标字段
		 * @param fieldValueMetaData
		 *            目标字段的元数据，通过它可以知道目标字段详细的数据类型(包括集合的泛型)
		 * @return Thrift支持的对象
	     * @throws Exception 
		 */
		private static Object parseField(Object fieldValue,
				FieldValueMetaData fieldValueMetaData) throws Exception {
			int thriftType = fieldValueMetaData.type;
			switch (thriftType) {
			case TType.STOP:
				break;
			case TType.VOID:
				break;
			case TType.BOOL: // 对应java的boolean
				if(StringUtils.isEmpty(fieldValue.toString()))
					return false;
				return Boolean.valueOf(fieldValue.toString());
			case TType.BYTE: // 对应java的byte
				if(StringUtils.isEmpty(fieldValue.toString()))
					return 0;
				return Byte.valueOf(fieldValue.toString());
			case TType.DOUBLE: // 对应java的double
				if(StringUtils.isEmpty(fieldValue.toString()))
					return 0.0;
				return Double.valueOf(fieldValue.toString());
			case TType.I16: // 对应java的short
			{
				if(StringUtils.isEmpty(fieldValue.toString()))
					return 0;
				
				String txt = fieldValue.toString();
				txt = StringUtils.substringBefore(txt, ".");
				return Short.valueOf(txt);
			}
			case TType.I32: // 对应java的int
			{
				if(StringUtils.isEmpty(fieldValue.toString()))
					return 0;
				
				String txt = fieldValue.toString();
				txt = StringUtils.substringBefore(txt, ".");
				return Integer.valueOf(txt);
			}
			case TType.I64: // 对应java的long
			{
				if(StringUtils.isEmpty(fieldValue.toString()))
					return 0;
				
				String txt = fieldValue.toString();
				txt = StringUtils.substringBefore(txt, ".");
				return Long.valueOf(txt);
			}
			case TType.STRING: // 对应java的String
				return fieldValue.toString();
			case TType.STRUCT: // 对应java的对象
			{
				if(fieldValue instanceof JSONObject)
					return parseStruct((JSONObject)fieldValue, (StructMetaData) fieldValueMetaData);
				break;
			}
				
			case TType.MAP: // 对应java的HashMap
			{	
				if(fieldValue instanceof JSONObject)
					return parseMap((JSONObject)fieldValue, (MapMetaData) fieldValueMetaData);
				break;
			}
			case TType.LIST: // 对应java的ArrayList
			{
				if(fieldValue instanceof JSONArray)
					return parseList((JSONArray)fieldValue, (ListMetaData) fieldValueMetaData);
				break;
			}
			case TType.ENUM: // 对应java的enum
			{
				if(fieldValue instanceof JSONObject)
					return parseEnum((JSONObject)fieldValue, (EnumMetaData) fieldValueMetaData);
				break;
			}
			}
			return null;
		}
	    
	    public static <T extends TBase, F extends TFieldIdEnum> T JsonNode2Thrift(JSONObject jsonNode, Class<T> thriftClass) throws Exception 
	    {
	    	
//	    	return JSON.parseObject(jsonNode.toJSONString(), thriftClass);
	    	
			T thriftObject = thriftClass.newInstance();
			Field metaDataMapField = thriftClass.getField("metaDataMap");
			Map<F, FieldMetaData> metaDataMap = (Map<F, FieldMetaData>) metaDataMapField.get(thriftObject);
			for (F field : metaDataMap.keySet()) {
				Object fieldJsonValue = jsonNode.get(field.getFieldName());
				if (fieldJsonValue == null)
					continue;
				FieldValueMetaData fieldValueMetaData = metaDataMap.get(field).valueMetaData;
				Object eleValue = null;
				try
				{
					eleValue = parseField(fieldJsonValue,fieldValueMetaData);
					thriftObject.setFieldValue(field, eleValue);
				}
				catch(Exception e)
				{
					String txt = "field name: " + field.getFieldName() + ", field type: " + fieldValueMetaData.type + ", fieldJsonValue: " + fieldJsonValue;
					throw new Exception(txt, e);
				}
			}
			return thriftObject;
		}
	    
	    public static <T extends TBase, F extends TFieldIdEnum> T JsonArray2ThriftArgs(JSONArray array, Class<T> thriftClass) throws Exception 
	    {
			T thriftObject = thriftClass.newInstance();
			Field metaDataMapField = thriftClass.getField("metaDataMap");
			Map<F, FieldMetaData> metaDataMap = (Map<F, FieldMetaData>) metaDataMapField.get(thriftObject);
			int i = 0;
			for (F field : metaDataMap.keySet()) 
			{
				Object fieldJsonValue = array.get(i++);
				if (fieldJsonValue == null)
					continue;
				FieldValueMetaData fieldValueMetaData = metaDataMap.get(field).valueMetaData;
				Object eleValue = null;
				try
				{
					eleValue = parseField(fieldJsonValue,fieldValueMetaData);
					thriftObject.setFieldValue(field, eleValue);
				}
				catch(Exception e)
				{
					String txt = "field name: " + field.getFieldName() + ", field type: " + fieldValueMetaData.type + ", fieldJsonValue: " + fieldJsonValue;
					throw new Exception(txt, e);
				}

			}
			return thriftObject;
		}
	    
}
